package  
{
	import com.buraks.utils.fastmem;
	import flash.utils.ByteArray;
	import starling.core.Starling;
	import starling.display.Sprite;
	import starling.events.Event;
	import starling.text.TextField;
	
	/**
	 * ...
	 * @author Guillaume Sylvain
	 */
	public class Game extends Sprite
	{
		private const MAX_BOID:int 			= 5000;
		private const RECORD_FRAME:int	 	= 60 * 5; // 60 fps * X seconds
		
		private var mStageWidth:int 		= 0;
		private var mStageHeight:int 		= 0;
		private var mRecordedFrame:int 		= 0;
		private var mScreenCenterX:Number 	= 0;
		private var mScreenCenterY:Number 	= 0;
		private var mBoidList:Vector.<Boid> = new Vector.<Boid>(MAX_BOID, true);
		private var mBoidData:ByteArray 	= new ByteArray();
		private var mRecordMode:Boolean 	= false;
		private var mProgressTxt:TextField	= null;
		
		public function Game() 
		{
			mStageWidth = Starling.current.stage.stageWidth;
			mStageHeight = Starling.current.stage.stageHeight;
			mScreenCenterX = mStageWidth / 2;
			mScreenCenterY = mStageHeight / 2;
			this.alpha = 0.999; // Optimization
			this.touchable = false;
			
			AddProgress();
			CreateBoids();
			
			mRecordMode = true;
			mBoidData.length = RECORD_FRAME * MAX_BOID * (Boid.DATA_SIZE);
			mBoidData.position = 0;
			fastmem.fastSelectMem(mBoidData);
			
			addEventListener(Event.ENTER_FRAME, OnEnterFrame);
		}
		
		private function StopRecording():void
		{
			mRecordMode = false;
			mRecordedFrame = 0;
			mBoidData.position = 0;
			mBoidDataPos = 0;
		}
		
		private function CreateBoids():void
		{
			// Create boids
			for (var i:int = 0; i < MAX_BOID; i++)
			{
				mBoidList[i] = new Boid(this);
			}
			
			// Assign
			for (i = 0; i < MAX_BOID; i++)
			{
				Assign(mBoidList[i], i);
				mBoidList[i].SetBindPos(mScreenCenterX, mScreenCenterY, mScreenCenterY);
				RandomPos(mBoidList[i]);
			}
		}
		
		private function Assign(aBoid:Boid, aIndex:int):void
		{
			var randomFriend1:int = 0;
			do
			{
				randomFriend1 = RandomInt(0, MAX_BOID - 1);
			}
			while (aIndex == randomFriend1)
			
			var randomFriend2:int = 0;
			do
			{
				randomFriend2 = RandomInt(0, MAX_BOID - 1);
			}
			while (aIndex == randomFriend2 || randomFriend1 == randomFriend2)
			
			aBoid.mFriend = mBoidList[randomFriend1];
			aBoid.mEnemy = mBoidList[randomFriend2];
		}
		
		private var mFrameCpt:int = 10;
		private var mBoidDataPos:int = 0;
		private function OnEnterFrame(aEvent:Event):void
		{
			var i:int = 0;
			
			if (mRecordMode)
			{
				for (i = 0; i < MAX_BOID; i++)
				{
					mBoidList[i].UpdatePos();
				}
				
				mFrameCpt--;
				
				if (mFrameCpt <= 0)
				{
					mFrameCpt = 10;
					
					var rnd:int = RandomInt(0, MAX_BOID - 1);
					Assign(mBoidList[rnd], rnd);
					RandomPos(mBoidList[rnd]);
				}
				
				for (i = 0; i < MAX_BOID; i++)
				{
					mBoidList[i].Serialize(mBoidData, mBoidDataPos);
					mBoidDataPos += Boid.DATA_SIZE;
				}
				
				mRecordedFrame++;
				UpdateProgress();
				
				if (mRecordedFrame >= RECORD_FRAME)
				{
					StopRecording();
					RemoveProgress();
				}
			}
			else
			{
				for (i = 0; i < MAX_BOID; i++)
				{
					mBoidList[i].Deserialize(mBoidData, mBoidDataPos);
					mBoidDataPos += Boid.DATA_SIZE;
				}
				
				mRecordedFrame++;
				
				if (mRecordedFrame >= RECORD_FRAME)
				{
					StopRecording();
				}
			}
		}
		
		private function AddProgress():void
		{
			// Progress textfield
			mProgressTxt = new TextField(270, 40, "", "Verdana", 20, 0xFFFFFF, true);
			mProgressTxt.x = mStageWidth / 2 - mProgressTxt.width / 2;
			mProgressTxt.y = mStageHeight / 2 - mProgressTxt.height / 2;
			addChild(mProgressTxt);
		}
		
		private function UpdateProgress():void
		{
			if (mProgressTxt)
			{
				mProgressTxt.text = "Processing data... " + Math.round(mRecordedFrame / RECORD_FRAME * 100) + "%";
			}
		}
		
		private function RemoveProgress():void
		{
			if (mProgressTxt)
			{
				removeChild(mProgressTxt);
				mProgressTxt = null;
			}
		}
		
		private function RandomInt(aMin:int, aMax:int):int
		{
			return (Math.floor(Math.random() * (aMax - aMin + 1)) + aMin); 
		}
		
		private function RandomNumber(aMin:Number, aMax:Number):Number
		{
			return aMin + (Math.random() * (aMax - aMin));
		}
		
		private function RandomPos(aBoid:Boid):void
		{
			aBoid.mPos.x = RandomNumber(0, mStageWidth);
			aBoid.mPos.y = RandomNumber(0, mStageHeight);
			aBoid.mPos.z = RandomNumber(0, mStageHeight);
		}
	}
}